﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace RpcGenerator.AS3
{
    class AS3RpcGenerator
    {
        public void Generator(Type type, string path)
        {
            MessageDescriptionGenerator mdgenerator = new MessageDescriptionGenerator();
            List<MessageDescription> allDescriptions = mdgenerator.Generate(type);

            Generate(type, path, allDescriptions, GenerateInterface);
            Generate(type, path, allDescriptions, GenerateInterfaceCallback);
            Generate(type, path, allDescriptions, GenerateInterfaceHelper);
            allDescriptions.ForEach(description => 
            {
                Generate(type, path, description, GenerateMessage);
            });
            Generate(type, path, allDescriptions, GenerateProxy);
            Generate(type, path, allDescriptions, GenerateInvoker);

            allDescriptions.ForEach(messageDescription =>
            {
                messageDescription.Fields.ForEach(fieldDescription =>
                {
                    if (!fieldDescription.IsPrimitiveType() && !fieldDescription.IsGenericType() && !fieldDescription.IsString())
                    {
                        Generate(type, path, fieldDescription, GenerateShareMessage);                        
                    }
                });
            });

            allDescriptions.ForEach(messageDescription =>
            {
                messageDescription.Fields.ForEach(fieldDescription =>
                {
                    if (fieldDescription.IsEnum())
                    {
                        Generate(type, path, fieldDescription, GenerateEnum);                                                
                    }
                });
            });
        }

        private string GenerateInterface(Type type, List<MessageDescription> allDescriptions, IMessageSerializer serializer)
        {            
            AS3InterfaceGenerator.Generate(type, serializer, allDescriptions);
            return string.Format("{0}{1}.as", GetFileDirectory(type), type.Name);
        }

        private string GenerateInterfaceCallback(Type type, List<MessageDescription> allDescriptions, IMessageSerializer serializer)
        {
            AS3InterfaceGenerator.GenerateCallback(type, serializer, allDescriptions);
            return string.Format("{0}{1}Callback.as", GetFileDirectory(type), type.Name);
        }

        private string GenerateInterfaceHelper(Type type, List<MessageDescription> allDescriptions, IMessageSerializer serializer)
        {
            AS3InterfaceHelperGenerator.Generate(type, serializer);
            return string.Format("{0}{1}Helper.as", GetFileDirectory(type), type.Name);            
        }

        private string GenerateMessage(Type type, MessageDescription description, IMessageSerializer serializer)
        {
            AS3MessageGenerator.Generate(description, serializer);
            return GetFileDirectory(type) + description.Name + ".as";
        }

        private string GenerateShareMessage(Type type, MessageFieldDescription description, IMessageSerializer serializer)
        {
            AS3ShareMessageGenerator.GenerateShareMessage(description, serializer);            
            return GetFileDirectory(type) + description.Type.Name + ".as";
        }

        private string GenerateEnum(Type type, MessageFieldDescription description, IMessageSerializer serializer)
        {
            AS3EnumGenerator.Generate(description,serializer);            
            return GetFileDirectory(type) + description.Type.Name + ".as";
        }

        private string GenerateProxy(Type type, List<MessageDescription> allDescriptions, IMessageSerializer serializer)
        {
            AS3ProxyGenerator.Generate(type, serializer, allDescriptions);
            return GetFileDirectory(type) + RpcGeneratorHelper.GetProxyName(type) + ".as";
        }

        private string GenerateInvoker(Type type, List<MessageDescription> allDescriptions, IMessageSerializer serializer)
        {
            AS3InvokerGenerator.Generate(type, serializer, allDescriptions);
            return GetFileDirectory(type) + RpcGeneratorHelper.GetInvokerName(type) + ".as";
        }

        private void Generate(Type type, string path, List<MessageDescription> allDescriptions, Func<Type, List<MessageDescription>,IMessageSerializer,string> GetContent)
        {
            DefaultMessageSerializer serializer = new DefaultMessageSerializer(0);

            NamespaceGenerator ngenerator = new NamespaceGenerator();
            MessageNamespace Namespace = ngenerator.Generate(type, allDescriptions, NamespaceType.AS3);
            serializer.Apppend(string.Format("package {0}", Namespace.Namespace));
            serializer.BeginBlock();
            Namespace.ReferenceNamespace.ForEach(reference =>
            {
                serializer.NewLine(string.Format("import {0};", reference));
            });

            serializer.NewLine();
            string file = GetContent(type, allDescriptions, serializer);
            serializer.EndBlock();
            string content = serializer.ToString();

            string fullpath = Path.Combine(path, file);
            FileGeneratorEx.GenerateAS3(fullpath, content);
        }

        private void Generate(Type type, string path, MessageDescription description, Func<Type, MessageDescription, IMessageSerializer, string> GetContent)
        {
            DefaultMessageSerializer serializer = new DefaultMessageSerializer(0);

            NamespaceGenerator ngenerator = new NamespaceGenerator();
            List<MessageDescription> allDescription = new List<MessageDescription>();
            allDescription.Add(description);
            MessageNamespace Namespace = ngenerator.Generate(type, allDescription, NamespaceType.AS3);
            serializer.Apppend(string.Format("package {0}", Namespace.Namespace));
            serializer.BeginBlock();
            Namespace.ReferenceNamespace.ForEach(reference =>
            {
                serializer.NewLine(string.Format("import {0};", reference));
            });

            serializer.NewLine();
            string file = GetContent(type, description, serializer);
            serializer.EndBlock();
            string content = serializer.ToString();

            string fullpath = Path.Combine(path, file);
            FileGeneratorEx.GenerateAS3(fullpath, content);
        }

        private void Generate(Type type, string path, MessageFieldDescription description, Func<Type, MessageFieldDescription, IMessageSerializer, string> GetContent)
        {
            DefaultMessageSerializer serializer = new DefaultMessageSerializer(0);

            NamespaceGenerator ngenerator = new NamespaceGenerator();
            MessageNamespace Namespace = ngenerator.Generate(description, NamespaceType.AS3);
            serializer.Apppend(string.Format("package {0}", Namespace.Namespace));
            serializer.BeginBlock();
            Namespace.ReferenceNamespace.ForEach(reference =>
            {
                serializer.NewLine(string.Format("import {0};", reference));
            });

            serializer.NewLine();
            string file = GetContent(type, description, serializer);
            serializer.EndBlock();
            string content = serializer.ToString();

            string fullpath = Path.Combine(path, file);
            FileGeneratorEx.GenerateAS3(fullpath, content);
        }

        private string GetFileDirectory(Type type)
        {
            StringBuilder sb = new StringBuilder();
            type.Namespace.Split('.').ToList().ForEach(s =>
            {
                sb.Append(s);
                sb.Append('/');
            });
            return sb.ToString();
        }
    }
}
